<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>CRUD</title>
    <style>
        table tr td {
            text-align: center;
        }
    
        template {
            display: none;
        }
    </style>
</head>
<body>
    <div id="app">
        <p><label>搜索:</label><input type="text" v-model="searchStr"></p>
        <grid-table :col-name-grid="colName" :table-data-grid="tableData" :search-str-grid="searchStr"></grid-table>
    </div>
    <template id="gridTable">
        <div>
            <p><add-or-update :col-name-grid="colNameGrid"></add-or-update></p>
            <table border="1">
                <thead>
                    <tr>
                        <td>No</td>
                        <td v-for="col in colNameGrid">{{ col.name | capitalize }}</td>
                        <td>Option</td>
                    </tr>
                </thead>
                <tbody>
                    <tr v-for="(user, index) in filteredData">
                        <td>{{ index + 1 }}</td>
                        <td v-for="property in user">{{ property }}</td>
                        <td>
                            <button @click="findUserByName(user.name)">修改</button>
                            <button @click="delUser(index)">删除</button>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
    </template>
    <template id="addOrUpdate">
        <table border="1">
            <tr v-for="col in colNameGrid">
                <td><label>{{ col.name }}:</label></td>
                <td>
                    <input v-if="col.type == 'input'" type="text" v-model="newUser[col.name]">
                    <select v-if="col.type == 'select'" v-model="newUser[col.name]">
                        <option v-for="opt in col.default" :value="opt">{{ opt }}</option>
                    </select>
                </td>
            </tr>
            <tr>
                <td colspan="2"><button @click="addOrUpdate">addOrUpdate</button></td>
            </tr>
        </table>
    </template>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    // 组件使用事件中心进行通信
    var eventHub = new Vue();
    
    // 建立公共方法，属性复制
    Vue.copyProperty = function (p, c) {
        c = c || {};
        for (var i in p) {
            // 属性i是否为p对象的自有属性
            if (p.hasOwnProperty(i)) {
                // 属性i是否为复杂类型
                if (typeof p[i] === 'object') {
                    // 如果p[i]是数组，则创建一个新数组
                    // 如果p[i]是普通对象，则创建一个新对象
                    c[i] = Array.isArray(p[i]) ? [] : {};
                    // 递归拷贝复杂类型的属性
                    this.copyProperty(p[i], c[i]);
                } else {
                    // 属性是基础类型时，直接拷贝
                    c[i] = p[i];
                }
            }
        }
        return c;
    }

    Vue.component('grid-table', {
        template: "#gridTable",
        props: {
            searchStrGrid: String,
            colNameGrid: Array,
            tableDataGrid: Array
        },
        filters: {
            // 首字母转大写
            capitalize: function(value) {
                if(!value){
                    return "";
                }
                value = value.toString();
                return value.charAt(0).toUpperCase() + value.slice(1);
            }
        },
        computed: {
            // 字符查找过滤
            filteredData: function () {
                var self = this;
                return this.tableDataGrid.filter(function (user) {
                    return user.name.toLowerCase().indexOf(self.searchStrGrid.toLowerCase()) != -1 ||
                        user.sex.toLowerCase().indexOf(self.searchStrGrid.toLowerCase()) != -1 ||
                        user.age.toString().toLowerCase().indexOf(self.searchStrGrid.toLowerCase()) != -1;
                });
            }
        },
        methods: {
            delUser: function(index) {
                this.tableDataGrid.splice(index, 1);
            },
            addOrUpdate: function(user) {
                for (var index = 0, len = this.tableDataGrid.length; index < len; index++) {
                    if(this.tableDataGrid[index].name == user.name){
                        /* this.tableDataGrid[index].name = user.name;
                        this.tableDataGrid[index].sex = user.sex;
                        this.tableDataGrid[index].age = user.age; */
                        // 用for不用一个个写
                        for (var col in user) {
                            this.tableDataGrid[index][col] = user[col];
                        }
                        // 使用下面这个方法对象替换了，但是属性还是没替换，重新加载表格就好了
                        // this.tableDataGrid[index] = Vue.copyProperty(user);
                        return;
                    }
                }
                this.tableDataGrid.push(user);
                // 查看父组件数据
                /* var rootData = this.$parent.tableData;
                for (var index = 0, len = rootData.length; index < len; index++) {
                    alert(rootData[index].name);
                } */
            },
            findUserByName: function(name) {
                var tableDataGrid = this.tableDataGrid;
                for (var index = 0, len = this.tableDataGrid.length; index < len; index++) {
                    if(tableDataGrid[index].name == name){
                        eventHub.$emit('findUserByName', tableDataGrid[index]);
                    }
                }
            }
        },
        components: {
            'add-or-update': {
                template: '#addOrUpdate',
                data: function(){
                    return {
                        newUser: {
                            name: '',
                            sex: '男',
                            age: 0
                        }
                    }
                },
                props: {
                    colNameGrid: Array
                },
                methods: {
                    addOrUpdate: function(){
                        // 在子组件中修改父组件不好的做法
                        // this.$parent.tableDataGrid.push(this.newUser);
                        // this.$root.tableData.push(this.newUser);
                        // 使用事件派发
                        if(this.newUser.name == ''){
                            alert('name is null');
                            return;
                        }
                        var reg = /^\d*$/;
                        if(!reg.test(this.newUser.age)){
                            alert('age is type error');
                            return;
                        }
                        var user = Vue.copyProperty(this.newUser);
                        eventHub.$emit('addOrUpdate', user);
                        this.newUser = {name: '', sex: '男', age: 0};
                    },
                    findUserByName: function(user){
                        // 直接赋值会将两个对象绑定
                        // this.newUser = user;
                        /* this.newUser.name = user.name;
                        this.newUser.sex = user.sex;
                        this.newUser.age = user.age; */
                        // 应该进行属性copy
                        this.newUser = Vue.copyProperty(user);
                    }
                },
                // 组件创建时启动监听
                created: function () {
                    eventHub.$on('findUserByName', this.findUserByName);
                },
                // 最好在组件销毁前清除监听
                beforeDestroy: function () {
                    eventHub.$off('findUserByName', this.findUserByName);
                }
            }
        },
        // 组件创建时启动监听
        created: function() {
            eventHub.$on('addOrUpdate', this.addOrUpdate);
        },
        // 最好在组件销毁前清除监听
        beforeDestroy: function() {
            eventHub.$off('addOrUpdate', this.addOrUpdate);
        }
    });
    
    var app = new Vue({
        el: '#app',
        data: {
            searchStr: '',
            colName: [{
                name: 'name',
                type: 'input',
                default: ''
            },{
                name: 'sex',
                type: 'select',
                default: ['男', '女']
            },{
                name: 'age',
                type: 'input',
                default: 0
            }],
            tableData: [{
                name: 'Jack',
                sex: '男',
                age: 32
            },{
                name: '王明',
                sex: '男',
                age: 43
            },{
                name: 'Lili',
                sex: '女',
                age: 24
            },{
                name: '李玲',
                sex: '女',
                age: 19
            }]
        }
    });
</script>
</html>